﻿using System;
using System.Drawing;
using System.Windows.Forms;
using Moonlite.Services.CodeCompletion;
using Moonlite.ExtensionApi.ControlInterfaces;
using Moonlite.ExtensionApi.GlobalInterfaces;
using Moonlite.Languages;
using Moonlite.Languages.vJass;
using Moonlite.Languages.vJass.CodeObj;
using Moonlite.Platform.General;
using Moonlite.Platform.Project;

namespace Moonlite.UI.Shell.Controls {
    public partial class ObjectBrowser : UserControl {
        public const int ImageIndexLibrary = 0;
        public const int ImageIndexMethod = 1;
        public const int ImageIndexScope = 2;
        public const int ImageIndexStruct = 3;
        public const int ImageIndexVariable = 4;

        private TreeNode GlobalsNode { get; set; }
        private ImageList ImageList { get; set; }
        private IParser parser;
        public IParser Parser {
            get { return parser; }
            set {
                parser = value;
                if (parser != null) {
                    UpdateParser();
                }
            }
        }

        public void UpdateParser() {
            treeView.Nodes.Clear();
            if (Global.Instance.Project.Type == ProjectType.Jass) {
                JParser parser = (JParser)Parser;
                foreach (Library library in parser.Libraries) {
                    if (library.Parent == null) {
                        ProcessLibrary(library, null);
                    }
                }

                foreach (Scope scope in parser.Scopes) {
                    if (scope.Parent == null) {
                        ProcessScope(scope, null);
                    }
                }

                foreach (Globals globals in parser.Globals) {
                    if (globals.Parent == null) {
                        ProcessGlobals(globals, null);
                    }
                }

                foreach (Function function in parser.Functions) {
                    if (function.Parent == null) {
                        ProcessFunction(function, null);
                    }
                }

                foreach (Struct @struct in parser.Structs) {
                    if (@struct.Parent == null) {
                        ProcessStruct(@struct, null);
                    }
                }
            }
        }

        private void ProcessLibrary(Library library, TreeNode parent) {
            TreeNode rootNode = new TreeNode { Text = library.Name, Tag = library, ImageIndex = ImageIndexLibrary, SelectedImageIndex = ImageIndexLibrary };
            foreach (Scope scope in library.Scopes) {
                ProcessScope(scope, rootNode);
            }

            foreach (Globals globals in library.Globals) {
                ProcessGlobals(globals, rootNode);
            }

            foreach (Struct @struct in library.Structs) {
                ProcessStruct(@struct, rootNode);
            }

            foreach (Function function in library.Functions) {
                ProcessFunction(function, rootNode);
            }

            if (parent == null) {
                treeView.Nodes.Add(rootNode);
            }
            else {
                parent.Nodes.Add(rootNode);
            }
        }

        private void ProcessScope(Scope scope, TreeNode parent) {
            TreeNode rootNode = new TreeNode { Text = scope.Name, Tag = scope, ImageIndex = ImageIndexScope, SelectedImageIndex = ImageIndexScope };
            foreach (Scope childScope in scope.Scopes) {
                ProcessScope(childScope, rootNode);
            }

            foreach (Globals globals in scope.Globals) {
                ProcessGlobals(globals, rootNode);
            }

            foreach (Struct @struct in scope.Structs) {
                ProcessStruct(@struct, rootNode);
            }

            foreach (Function function in scope.Functions) {
                ProcessFunction(function, rootNode);
            }

            if (parent == null) {
                treeView.Nodes.Add(rootNode);
            }
            else {
                parent.Nodes.Add(rootNode);
            }
        }

        private void ProcessGlobals(Globals globals, TreeNode parent) {
            TreeNode rootNode = GlobalsNode == null ? new TreeNode { Text = "Globals", Tag = globals, ImageIndex = ImageIndexVariable, SelectedImageIndex = ImageIndexVariable } : GlobalsNode;
            if (GlobalsNode == null) {
                GlobalsNode = rootNode;
                if (parent == null) {
                    treeView.Nodes.Add(GlobalsNode);
                }
                else {
                    parent.Nodes.Add(GlobalsNode);
                }
            }

            foreach (GlobalVariable variable in globals.GlobalVariables) {
                rootNode.Nodes.Add(new TreeNode { Text = variable.Name, Tag = variable, ImageIndex = ImageIndexVariable, SelectedImageIndex = ImageIndexVariable });
            }
        }

        private void ProcessFunction(Function function, TreeNode parent) {
            TreeNode rootNode = new TreeNode { Text = function.Name, Tag = function, ImageIndex = ImageIndexMethod, SelectedImageIndex = ImageIndexMethod };
            foreach (FunctionVariable variable in function.Variables) {
                rootNode.Nodes.Add(new TreeNode { Text = variable.Name, Tag = variable, ImageIndex = ImageIndexVariable, SelectedImageIndex = ImageIndexVariable });
            }

            if (parent == null) {
                treeView.Nodes.Add(rootNode);
            }
            else {
                parent.Nodes.Add(rootNode);
            }
        }

        private void ProcessStruct(Struct @struct, TreeNode parent) {
            TreeNode rootNode = new TreeNode { Text = @struct.Name, Tag = @struct, ImageIndex = ImageIndexStruct, SelectedImageIndex = ImageIndexStruct };
            foreach (Member member in @struct.Members) {
                rootNode.Nodes.Add(new TreeNode { Text = member.Name, Tag = member, ImageIndex = ImageIndexVariable, SelectedImageIndex = ImageIndexVariable });
            }

            foreach (Method method in @struct.Methods) {
                ProcessMethod(method, rootNode);
            }

            if (parent == null) {
                treeView.Nodes.Add(rootNode);
            }
            else {
                parent.Nodes.Add(rootNode);
            }
        }

        private void ProcessMethod(Method method, TreeNode parent) {
            TreeNode rootNode = new TreeNode { Text = method.Name, Tag = method, ImageIndex = ImageIndexMethod, SelectedImageIndex = ImageIndexMethod };
            foreach (MethodVariable variable in method.Variables) {
                rootNode.Nodes.Add(new TreeNode { Text = variable.Name, Tag = variable, ImageIndex = ImageIndexVariable, SelectedImageIndex = ImageIndexVariable });
            }

            if (parent == null) {
                treeView.Nodes.Add(rootNode);
            }
            else {
                parent.Nodes.Add(rootNode);
            }
        }

        private void OnTreeViewNodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e) {
            if (GlobalsNode != null && e.Node == GlobalsNode) {
                return;
            }

            if (e.Node != null && e.Node.Tag != null && e.Node.Tag is Obj) {
                Obj obj = (Obj)e.Node.Tag;
                if (Global.Instance.IsCurrentTabPageTextEditor() == true) {
                    ITextEditor textEditor = Global.Instance.GetCurrentTabPageTextEditor();
                    textEditor.InnerTextEditor.ActiveViewControl.CenterInView(obj.StartLine);
                    textEditor.InnerTextEditor.Caret.Position.Y = obj.StartLine;
                    Moonlite.Shell.SelectLine(textEditor);
                }
            }
        }

        public void UpdateImageList() {
            if (Global.Instance == null || Global.Instance.Project == null) return;
            if (Global.Instance.Project.Type == ProjectType.Jass) treeView.ImageList = JassCompletionDataProvider.GlobalImageList;
            else if (Global.Instance.Project.Type == ProjectType.Galaxy) treeView.ImageList = AndromedaImageIndexes.GlobalImageList;
        }

        public ObjectBrowser() {
            InitializeComponent();
        }
    }
}
